package eecs285.proj4.gui;

//Class: EECS 285
//Project: 
//Due Date: Monday December 6th, 2010

//NOTES: 


import java.awt.Canvas;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.swing.ImageIcon;
import javax.swing.text.Document;
import eecs.net.xmpp.DataListener;
import eecs.util.MException;
import static eecs.util.Utility.*;

// -----------------------------------------------------------------------------
// ----- BEGIN Class Definition (MarkerboardListener) --------------------------

/**
 * Listener class to handle both user events and network events.
 * 
 * @author Vidal Borromeo
 * @author Matt Muccioli
 * @author Hans Marquard
 * @author Easton Thomas
 */
public class MarkerboardListener implements DataListener, ActionListener
{
  Markerboard parent;
  MarkerboardCanvas canvas_parent;
  
  
  // ---------------------------------------------------------------------------

  MarkerboardListener(Markerboard parent_, MarkerboardCanvas canvas_parent_)
  {
    parent = parent_; 
    canvas_parent = canvas_parent_;
  }// ctor

  // ---------------------------------------------------------------------------

  @Override
  public void actionPerformed(ActionEvent e)
  {
    canvas_parent.textDone(); //if we need to finish text
    if( e.getSource() == parent.loadMarkerboardMenuItem )
    {
      parent.loadMarkerboard();
      return;
    }
    else if( e.getSource() == parent.saveMarkerboardMenuItem )
    {
      parent.saveMarkerboard();
      return;
    }
    else if( e.getSource() == parent.saveImageMenuItem )
    {
      parent.saveImage();
      return;
    }
    else if( e.getSource() == parent.exitProgramMenuItem )
    {
      parent.exitProgram();
      return;
    }
    else if( e.getSource() == parent.zoomInMenuItem )
    {
      parent.zoomIn();
      return;
    }
    else if( e.getSource() == parent.zoomOutMenuItem )
    {
      parent.zoomOut();
      return;
    }
    else if( e.getSource() == parent.zoomResetMenuItem )
    {
      parent.zoomReset();
      return;
    }
    else if( e.getSource() == parent.resizeCanvasMenuItem )
    {
      parent.resizeCanvas();
      return;
    }
    //ColorChooser
    else if( e.getSource() == parent.colorChooserComboBox )
    {
      parent.canvas.setCursor(parent.setCursorColor());
      return;
    }
    // Select Draw Type
    else if( e.getSource() == parent.freeDrawButton )
    {
      parent.canvas.setCursor(parent.setCursorColor());
      canvas_parent.setType(MAction.TYPE.FREEDRAW);
      parent.freeDrawButton.setBackground(Color.GRAY);
      parent.lineButton.setBackground(null);
      parent.rectangleButton.setBackground(null);
      parent.circleButton.setBackground(null);
      parent.textButton.setBackground(null);
      parent.eraseButton.setBackground(null);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.lineButton )
    {
      parent.setCursorColor();
      parent.canvas.setCursor(parent.setCursorColor());
      canvas_parent.setType(MAction.TYPE.LINE);
      parent.freeDrawButton.setBackground(null);
      parent.lineButton.setBackground(Color.GRAY);
      parent.rectangleButton.setBackground(null);
      parent.circleButton.setBackground(null);
      parent.textButton.setBackground(null);
      parent.eraseButton.setBackground(null);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.rectangleButton )
    {
      parent.setCursorColor();
      parent.canvas.setCursor(parent.setCursorColor());
      canvas_parent.setType(MAction.TYPE.RECTANGLE);
      parent.freeDrawButton.setBackground(null);
      parent.lineButton.setBackground(null);
      parent.rectangleButton.setBackground(Color.GRAY);
      parent.circleButton.setBackground(null);
      parent.textButton.setBackground(null);
      parent.eraseButton.setBackground(null);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.circleButton )
    {
      parent.setCursorColor();
      parent.canvas.setCursor(parent.setCursorColor());
      canvas_parent.setType(MAction.TYPE.CIRCLE);
      parent.freeDrawButton.setBackground(null);
      parent.lineButton.setBackground(null);
      parent.rectangleButton.setBackground(null);
      parent.circleButton.setBackground(Color.GRAY);
      parent.textButton.setBackground(null);
      parent.eraseButton.setBackground(null);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.textButton )
    {
      parent.canvas.setCursor(new Cursor(Cursor.TEXT_CURSOR));
      canvas_parent.setType(MAction.TYPE.TEXT);
      parent.freeDrawButton.setBackground(null);
      parent.lineButton.setBackground(null);
      parent.rectangleButton.setBackground(null);
      parent.circleButton.setBackground(null);
      parent.textButton.setBackground(Color.GRAY);
      parent.eraseButton.setBackground(null);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.eraseButton )
    {
      parent.canvas.setCursor(parent.Eraser_Curser);
      canvas_parent.setType(MAction.TYPE.ERASE);
      parent.freeDrawButton.setBackground(null);
      parent.lineButton.setBackground(null);
      parent.rectangleButton.setBackground(null);
      parent.circleButton.setBackground(null);
      parent.textButton.setBackground(null);
      parent.eraseButton.setBackground(Color.GRAY);
      parent.clearButton.setBackground(null);
      parent.undoButton.setBackground(null);
      return;
    }
    else if( e.getSource() == parent.clearButton )
    {
      // Create gigantic white line that fills the screen
      canvas_parent.action = new Line(new Point(0, 0), new Point(
          canvas_parent.getWidth(), canvas_parent.getHeight()));
      canvas_parent.action.mine = true;
      canvas_parent.action.setColor(Color.white);
      canvas_parent.action.setStroke((canvas_parent.getHeight() * canvas_parent
          .getWidth()));
      canvas_parent.addToActionList(canvas_parent.action);
      // broadcasting here
      try
      {
        parent.connection.broadcast(Markerboard.KEY_DRAW_ACTION, canvas_parent.action);
      }
      catch( IOException e1 )
      {
        // TODO Auto-generated catch block
        // e1.printStackTrace();
        debug("Could not send action.");
      }
      canvas_parent.action = null;

      return;
    }
    else if( e.getSource() == parent.undoButton )
    {
      synchronized( canvas_parent.actionList )
      {
        for (int i = canvas_parent.actionList.size() - 1; i >= 0; i--)
        {
          if( canvas_parent.actionList.get(i).mine.equals(true) )
          {
            try
            {
              parent.connection.broadcast(Markerboard.KEY_ACTION_UNDO, canvas_parent.actionList.remove(i));
            }
            catch( IOException e1 )
            {
              // TODO Auto-generated catch block
              //e1.printStackTrace();
            }
            break;
          }// if
        }// for
      }
      return;

    }// else-if
    
    // TODO Add color chooser

    // Left Area
    else if( e.getSource() == parent.connectButton )
    {
      parent.sessionID = parent.sessionIDTextField.getText();

      // parent.connect(parent.sessionID);
      // if (parent.connection.isConnected() == true){
      if( parent.connect(parent.sessionID) )
      {
        parent.sessionIDTextField.setEditable(false);
        parent.userNameTextField.setEditable(false);
        parent.connectButton.setEnabled(false);
        parent.disconnectButton.setEnabled(true);
        parent.chatArea.setBackground(Color.WHITE);
        parent.typingArea.setEditable(true);
        parent.typingArea.setBackground(Color.WHITE);
        parent.sendButton.setEnabled(true);
      }

      return;

    }// else-if

    else if( e.getSource() == parent.disconnectButton )
    {
      parent.disconnect();
      if( parent.connection.isConnected() == false )
      {
        parent.sessionIDTextField.setEditable(true);
        parent.userNameTextField.setEditable(true);
        parent.connectButton.setEnabled(true);
        parent.disconnectButton.setEnabled(false);
        parent.chatArea.setBackground(null);
        parent.typingArea.setEditable(false);
        parent.typingArea.setBackground(null);
        parent.sendButton.setEnabled(false);
      }
      return;
    }
    else if( e.getSource() == parent.sendButton )
    {
      parent.sendChatMessage();
      return;
    }


  }// actionPerformed

  // ---------------------------------------------------------------------------

  @Override
  public void dataReceived(final Map<String, Object> properties)
  {
    // Data was received over the network.


    if( properties.containsKey(Markerboard.KEY_ANNOUNCE) )
    {
      debug("Responding to Announce.");
      try
      {
        parent.connection.broadcast(Markerboard.KEY_ANNOUNCE_RESPONSE,
            parent.getUser());
      }
      catch( IOException e )
      {
        debug("Could not send Announce RESPONSE.");
        // e.printStackTrace();
      }
      // map.put()
      return;
    }
    else if( properties.containsKey(Markerboard.KEY_ANNOUNCE_RESPONSE) )
    {

      synchronized( parent.outstandingAnnounce )
      {
        if( !parent.outstandingAnnounce )
        {
          debug("Ignoring Annnounce Response.");
          return;
        }
        
        String first_responder = (String) properties
            .get(Markerboard.KEY_ANNOUNCE_RESPONSE);

          parent.sendSyncRequest(first_responder);

      }// sync

      return;
    }
    else if( properties.containsKey(Markerboard.KEY_SYNC_REQUEST) )
    { // Process request from new user.

      String desired_responder = (String) properties.get(Markerboard.KEY_SYNC_REQUEST);
      if(!parent.getUser().equals(desired_responder))
      {
        debug("Ignoring Sync Request.");
        return;
      }
      
      debug("Responding to Sync Request.");

      // ASSERT: WE ARE THE DESIRED RESPONDER.
      
      String requester = (String) properties
          .get(Markerboard.KEY_SYNC_REQUESTER);
      
      parent.userList.add(requester);
      

      Map<String, Object> map = new TreeMap<String, Object>();
      byte[] image = parent.markerboard_canvas.get_image();
      map.put(Markerboard.KEY_SYNC_RESPONSE, image);
      map.put(Markerboard.KEY_SYNC_REQUESTER, requester);
      map.put(Markerboard.KEY_SYNC_RESPONSE_USERS, parent.userList);
      // map.put(Markerboard.KEY_SYNC_RESPONSE_ACTIONCOUNT, )

      try
      {
        parent.connection.broadcast(map);
//        parent.connection.broadcast(Markerboard.KEY_SYNC_REQUESTER, requester,
//            Markerboard.KEY_SYNC_RESPONSE,
//            parent.markerboard_canvas.get_image());
      }
      catch( IOException e )
      {
        debug("Could not send Sync Response.");
        stackTrace(e);
      }

      return;
    }
    else if( properties.containsKey(Markerboard.KEY_SYNC_RESPONSE) )
    { // Receive the response to a Sync request (after joining a session).
      
      synchronized( parent.outstandingSyncRequest )
      {
        debug("outstandingSyncRequest: " +  parent.outstandingSyncRequest);
        if( !parent.outstandingSyncRequest )
        {
          debug("Ignoring Sync Response.");
          return;
        }
        
        // ASSERT: This is at least a valid response to a sync request for this session.
        //  AND... we want a sync response, so we'll take it.
        
        debug("Reading Response to Our Sync Request.");

        byte[] response = (byte[]) properties
            .get(Markerboard.KEY_SYNC_RESPONSE);
        String requester = (String) properties
            .get(Markerboard.KEY_SYNC_REQUESTER);
        parent.userList = (Set<String>) properties
            .get(Markerboard.KEY_SYNC_RESPONSE_USERS);

        debug("Requestor == " + requester);
        debug("My Name == " + parent.getUser());

        
        canvas_parent.set_image(response);
        parent.outstandingSyncRequest = false;
      }// sync

      return;
    }
    else if( properties.containsKey(Markerboard.KEY_DRAW_ACTION) )
    {
      MAction action = (MAction) properties.get(Markerboard.KEY_DRAW_ACTION);
      // Add to action queue and print
      canvas_parent.addToActionList(action);


      return;
    }
    else if( properties.containsKey(Markerboard.KEY_CHAT_MESSAGE) )
    {
      String msg = (String) properties.get(Markerboard.KEY_CHAT_MESSAGE);
      String author = (String) properties.get(Markerboard.KEY_CHAT_AUTHOR);
      parent.addMessage(author, msg);
      debug("Received Chat Message from " + author);
      debug("Message: " + msg);

      // Scroll to bottom of chatArea
      Document chatDocument = parent.chatArea.getDocument();
      parent.chatArea
          .select(chatDocument.getLength(), chatDocument.getLength());
      return;
    }
    else if( properties.containsKey(Markerboard.KEY_ACTION_UNDO) )
    {
      canvas_parent.undo((MAction) properties.get(Markerboard.KEY_ACTION_UNDO));
    }
  }// dataReceived

  // ---------------------------------------------------------------------------

  @Override
  public synchronized void incomingSemaphore()
  {
    parent.animateIn.startAnimation();
    //parent.animateIn.paintgreen();
  }// incomingSemaphore

  // ---------------------------------------------------------------------------

  @Override
  public synchronized void outgoingSemaphore()
  {
    parent.animateOut.startAnimation();
    //parent.animateOut.paintgreen();

  }// outgoingSemaphore

}// MarkerboardListener


// ----- END Class Definition (MarkerboardListener) ----------------------------
// -----------------------------------------------------------------------------
